namespace BM.Tools.WebControls.MForm.Controls
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Web.UI;
    using System.Xml.Schema;
    using System.Xml.XPath;

    using BM.Tools.WebControls.MForm.Controls.DefaultTemplates;
    using BM.Tools.WebControls.MForm.Controls.Helper;
    using BM.Tools.WebControls.MForm.Controls.Items;
    using BM.Tools.WebControls.MForm.Controls.Modifiers;
    using BM.Tools.WebControls.MForm.Design;

    using ValueFormatters;

    /// <summary>
    /// Leaf is an <see cref="Offspring" /> control that corresponds to terminal xml nodes
    /// </summary>
    [Designer(typeof(LeafDesigner))]
    public class Leaf : Offspring
    {
        private Collection<StringFormatter> valueFormatters = new Collection<StringFormatter>();

        /// <summary>
        /// Initializes a new instance of the <see cref="Leaf"/> class.
        /// </summary>
        public Leaf()
        {
            DataType = XmlTypeCode.String;
            DefaultValue = String.Empty;
            LeafType = LeafType.Element;
            Modifiers = new ModifiersCollection<LeafModifier, Leaf, LeafItem>(this);
        }

        /// <summary>
        /// Gets or sets DataType.
        /// </summary>        
        [DefaultValue(XmlTypeCode.String)]
        public XmlTypeCode DataType
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the default value of the leaf.
        /// </summary>        
        [DefaultValue("")]
        public string DefaultValue
        {
            get;
            set;
        }

        /// <summary>
        /// Gets a value indicating whether the control is optional. 
        /// It is optional when it can appear either never or at most once.
        /// </summary>        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual bool IsOptional
        {
            get
            {
                return MinOccurs == 0 && MaxOccurs == 1;
            }
        }

        /// <summary>
        /// Gets or sets LabelHolder.
        /// </summary>        
        [PersistenceMode(PersistenceMode.InnerProperty), NotifyParentProperty(true)]
        public ITemplate LabelHolder
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the leaf type - can be either <see cref="Helper.LeafType.Attribute"/> or <see cref="Helper.LeafType.Element"/> .
        /// </summary>        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), DefaultValue(Helper.LeafType.Element)]
        public LeafType LeafType
        {
            get;
            set;
        }

        /// <summary>
        /// Gets Modifiers.
        /// </summary>        
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [NotifyParentProperty(true)]
        public Collection<LeafModifier> Modifiers
        {
            get;
            private set;            
        }

        /// <summary>
        /// Gets ValueFormatters.
        /// </summary>
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public Collection<StringFormatter> ValueFormatters
        {
            get
            {
                return valueFormatters;
            }
        }

        /// <summary>
        /// Gets or sets the value handler.
        /// </summary>        
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate ValueHandler
        {
            get; 
            set;
        }

        internal override string XPathName
        {
            get
            {
                if (LeafType == LeafType.Element)
                {
                    return base.XPathName;
                }

                return "@" + LocalName;
            }
        }

        /// <summary>
        /// Gets information how many items should be rendered at least by default.
        /// This value will be used if the <see cref="Offspring.MinRenderedOccurs" /> was not set.
        /// By default in case of a <see cref="Leaf"/>, the item is rendered once if it is optional.
        /// </summary>       
        protected override int DefaultMinRenderedOccurs
        {
            get
            {
                return MaxOccurs == 1 ? 1 : base.DefaultMinRenderedOccurs;
            }
        }       

        /// <summary>        
        /// Creates a <see cref="LeafItem" /> object from the definitions specified in this object.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="navigator">
        /// The navigator.
        /// </param>
        /// <returns>
        /// the <see cref="LeafItem" /> object
        /// </returns>
        protected override OffspringItem CreateItem(int index, XPathNavigator navigator)
        {
            return new LeafItem(this, index, navigator);
        }

        private void ResetLabelHolder()
        {
            LabelHolder = new DefaultLabelTemplate(this);
        }

        private bool ShouldSerializeLabelHolder()
        {
            return !(LabelHolder is DefaultLabelTemplate);
        }
    }
}